﻿#region Using namespaces

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Data;
using System.Windows.Media;

#endregion

namespace BOL.Apps.GeneNetworkBrowser.Converters
{
    public static class ColorSystems
    {
        // Given H,S,L in range of 0-1
        // Returns a Color (RGB struct) in range of 0-255
        public static Color FromHSL(double h, double s, double l)
        {
            if (h < 0 || h > 1)
                throw new ArgumentOutOfRangeException("Hue should be between 0 and 1.");
            if (s < 0 || s > 1)
                throw new ArgumentOutOfRangeException("Saturation should be between 0 and 1.");
            if (l < 0 || l > 1)
                throw new ArgumentOutOfRangeException("Lightness should be between 0 and 1.");

            double v;
            double r, g, b;

            r = l; // default to gray
            g = l;
            b = l;
            v = (l <= 0.5) ? (l * (1.0 + s)) : (l + s - l * s);

            if (v > 0)
            {
                double m;
                double sv;
                int sextant;
                double fract, vsf, mid1, mid2;

                m = l + l - v;
                sv = (v - m) / v;
                h *= 6.0;
                sextant = (int)h;
                fract = h - sextant;
                vsf = v * sv * fract;
                mid1 = m + vsf;
                mid2 = v - vsf;

                switch (sextant)
                {
                    case 0:
                        r = v;
                        g = mid1;
                        b = m;
                        break;
                    case 1:
                        r = mid2;
                        g = v;
                        b = m;
                        break;
                    case 2:
                        r = m;
                        g = v;
                        b = mid1;
                        break;
                    case 3:
                        r = m;
                        g = mid2;
                        b = v;
                        break;
                    case 4:
                        r = mid1;
                        g = m;
                        b = v;
                        break;
                    case 5:
                        r = v;
                        g = m;
                        b = mid2;
                        break;
                }
            }

            byte R = Convert.ToByte(r * 255);
            byte G = Convert.ToByte(g * 255);
            byte B = Convert.ToByte(b * 255);

            return Color.FromArgb(255, R, G, B);
        }

        public static Color FromHSV(double h, double s, double v)
        {
            if (h < 0 || h > 1)
                throw new ArgumentOutOfRangeException("Hue should be between 0 and 1.");
            if (s < 0 || s > 1)
                throw new ArgumentOutOfRangeException("Saturation should be between 0 and 1.");
            if (v < 0 || v > 1)
                throw new ArgumentOutOfRangeException("Value should be between 0 and 1.");

            double H = h;
            while (H < 0) { H += 360; };
            while (H >= 360) { H -= 360; };
            double r, g, b;
            if (v <= 0)
            { r = g = b = 0; }
            else if (s <= 0)
            {
                r = g = b = v;
            }
            else
            {
                double hf = H / 60.0;
                int i = (int)Math.Floor(hf);
                double f = hf - i;
                double pv = v * (1 - s);
                double qv = v * (1 - s * f);
                double tv = v * (1 - s * (1 - f));
                
                switch (i)
                {
                    case 0: // Red is the dominant color
                        r = v;
                        g = tv;
                        b = pv;
                        break;
                    case 1: // Green is the dominant color
                        r = qv;
                        g = v;
                        b = pv;
                        break;
                    case 2:
                        r = pv;
                        g = v;
                        b = tv;
                        break;
                    case 3: // Blue is the dominant color
                        r = pv;
                        g = qv;
                        b = v;
                        break;
                    case 4:
                        r = tv;
                        g = pv;
                        b = v;
                        break;
                    case 5: // Red is the dominant color
                        r = v;
                        g = pv;
                        b = qv;
                        break;
                    case 6: // Just in case we overshoot on our math by a little, we put these here. Since its a switch it won't sow us down at all to put these here.
                        r = v;
                        g = tv;
                        b = pv;
                        break;
                    case -1:
                        r = v;
                        g = pv;
                        b = qv;
                        break;
                    default: // The color is not defined, we should throw an error.
                        //LFATAL("i Value error in Pixel conversion, Value is %d", i);
                        r = g = b = v; // Just pretend its black/white
                        break;
                }
            }

            byte R = Convert.ToByte(r * 255);
            byte G = Convert.ToByte(g * 255);
            byte B = Convert.ToByte(b * 255);

            return Color.FromArgb(255, R, G, B);
        }
    }
}
